import {Component} from '@angular/core';
import {BaseApiComponent} from '../page-api/base-api.component';
import {PageVoService} from '../../service/page-vo.service';
import {ActivatedRoute, Router} from '@angular/router';
import {DocService} from '../../service/doc.service';
import {MessageService} from '../../service/message.service';
import {MockUtils} from '../../utils/mock-utils';
import {MockConfigItem} from '../../entity/mock-config-item';
import {MockService} from '../../service/mock.service';
import {deepCopy, EntityUtils} from '../../utils/entity-utils';
import {AlertMessage} from '../../entity/alert-message';
import {MockConfig} from '../../entity/mock-config';
import {MockConditionRest} from '../../entity/mock-condition-rest';
import {MockConditionItem} from '../../entity/mock-condition-item';

@Component({
    selector: 'app-page-api-mock',
    templateUrl: './page-api-mock.component.html',
    styleUrls: ['./page-api-mock.component.css']
})
export class PageApiMockComponent extends BaseApiComponent {
    mockId: string;

    title = '';

    jsonResponse = '';

    mockConfigItem: MockConfigItem;

    condition: MockConditionRest;

    previewStr: string;

    loopedEntityMap: Map<string, MockConfigItem> = new Map<string, MockConfigItem>();

    constructor(protected pageVoService: PageVoService,
                protected activatedRoute: ActivatedRoute,
                protected router: Router,
                protected docService: DocService,
                protected messageService: MessageService,
                private mockService: MockService
    ) {
        super(pageVoService, activatedRoute, router, docService, messageService);
    }

    data: any;

    showOpts = false;

    isEditOpts = true;

    mockTypeTabStatus = 'config';

    protected onApiReady() {
        const mockId = this.activatedRoute.snapshot.paramMap.get('mockId');
        if (mockId === 'new') {
            // 新增
            this.initMockPageData();
            this.initRestConditionData();
            this.preview();
        } else {
            // 从服务端加载
            this.mockService.getById(this.docId, this.apiId, mockId).subscribe(resp => {
                if (resp.code !== 200) {
                    this.messageService.add(AlertMessage.error(resp.message));
                    return;
                } else {
                    const mockConfig = resp.data;
                    this.condition = mockConfig.restCondition;
                    this.recoverLoadedChildren(mockConfig.response);
                    this.mockConfigItem = mockConfig.response;
                    this.title = mockConfig.title;
                    this.mockId = mockId;

                    this.preview();
                }
            });
        }

        MockUtils.mockInfoProvider.subscribe((message: AlertMessage) => {
            if (message) {
                this.messageService.add(message);
            }
        });
    }

    initMockPageData() {
        this.showOpts = true;
        this.isEditOpts = false;
        const loopedEntityMap = new Map<string, MockConfigItem>();
        this.mockConfigItem = MockUtils.getMockConfig(this.api.response, this.docService, loopedEntityMap);
        loopedEntityMap.forEach((value, key) => {
            this.loopedEntityMap.set(key, deepCopy(value));
        });
    }

    save() {
        const mockConfig = this.genMockConfig();
        this.mockService.save(mockConfig).subscribe(resp => {
            if (resp.code !== 200) {
                this.messageService.add(AlertMessage.error(resp.message));
                return;
            }
            this.mockId = resp.data;
            this.messageService.add(AlertMessage.success('Mock配置保存成功'));

            this.router.navigate(['/doc', this.docId, this.apiId, 'mock', this.mockId]);
        });
    }

    private genMockConfig() {
        const mockConfig = <MockConfig>{
            title: this.title,
            docId: this.docId,
            apiId: this.apiId,
            response: this.mockConfigItem,
            restCondition: this.condition,
            responseType: this.mockTypeTabStatus === 'config' ? 0 : 1
        };
        if (this.mockId) {
            mockConfig.id = this.mockId;
        }
        if (mockConfig.responseType === 1) {
            mockConfig.jsonResponse = this.jsonResponse;
        }
        return mockConfig;
    }

    private initRestConditionData() {
        if (!this.api) {
            return;
        }
        if (!this.api.methods) {
            this.api.methods = ['GET', 'POST'];
        }

        const restCondition = <MockConditionRest>{
            pathParams: [],
            headerParams: [],
            urlParams: []
        };

        // 初始化参数
        const requestParams = this.api.requestParams;
        if (requestParams) {
            requestParams.forEach(param => {
                if (param.annotation === '@PathVariable') {
                    const pathParam = <MockConditionItem>{
                        key: param.name,
                        value: '',
                        operator: '==',
                        available: false
                    };

                    restCondition.pathParams.push(pathParam);
                } else if (param.annotation === '@RequestParam') {
                    // 检查是否复杂体，如果是，需要展开
                    const entity = this.docService.getEntity(param.entityName);
                    if (EntityUtils.isPrimitive(entity) || entity.enumerate) {
                        // 简单类型，直接使用
                        const pathParam = <MockConditionItem>{
                            key: param.name,
                            value: param.demo,
                            operator: '==',
                            available: false
                        };

                        restCondition.urlParams.push(pathParam);
                    } else {
                        if (entity.fields) {
                            entity.fields.forEach(field => {
                                const pathParam = <MockConditionItem>{
                                    key: field.name,
                                    value: field.demo,
                                    operator: '==',
                                    available: false
                                };
                            });
                        }
                    }
                }
            });
        }

        restCondition.headerParams.push(MockUtils.emptyMockConditionItem());
        restCondition.urlParams.push(MockUtils.emptyMockConditionItem());
        this.condition = restCondition;
    }

    preview() {
        const mockConfig = this.genMockConfig();
        this.previewStr = null;
        this.mockService.preview(mockConfig).subscribe(resp => {
            if (resp) {
                this.previewStr = resp.toString();
            }
        });
    }

    private recoverLoadedChildren(mockConfigItem: MockConfigItem) {
        if (mockConfigItem.loaded && !mockConfigItem.children) {
            mockConfigItem.children = [];
        }
        if (mockConfigItem.children && mockConfigItem.children.length > 0) {
            mockConfigItem.children.forEach(item => {
                this.recoverLoadedChildren(item);
            });
        }
        if (mockConfigItem.type === 2 && mockConfigItem.children && mockConfigItem.children.length > 0 && !this.loopedEntityMap.has(mockConfigItem.entityName)) {
            this.loopedEntityMap.set(mockConfigItem.entityName, deepCopy(mockConfigItem));
        }
    }

    setMockTypeTabStatus(status: string) {
        this.mockTypeTabStatus = status;
    }

    showDirectOutputDemo() {
        this.jsonResponse = '{\n\t"text": "hello duo-doc"\n}';
        this.preview();
    }
}
